/*!
 * \file WtStraDualThrust.cpp
 * \project WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief WonderTrader DualThrust双推策略实现文件
 * 
 * \details 该文件实现了WtStraDualThrust类的完整功能，提供经典的DualThrust策略算法：
 *          
 *          策略核心算法：
 *          1. 数据获取：获取最近N天的OHLC历史数据
 *          2. 区间计算：
 *             - HH = N天内最高价的最大值
 *             - LL = N天内最低价的最小值  
 *             - HC = N天内收盘价的最大值
 *             - LC = N天内收盘价的最小值
 *             - Range = max(HH-LC, HC-LL)
 *          3. 轨道计算：
 *             - 上轨 = 开盘价 + K1 * Range
 *             - 下轨 = 开盘价 - K2 * Range
 *          4. 交易信号：
 *             - 高点突破上轨：开多仓
 *             - 低点跌破下轨：开空仓（期货）
 *             - 反向突破：平仓
 *          
 *          支持市场：
 *          - 期货市场：支持双向交易（多空）
 *          - 股票市场：仅支持做多交易
 *          
 *          风险控制：
 *          - 使用decimal模块进行精确浮点数比较
 *          - 自动资源管理，防止内存泄漏
 *          - 股票交易单位转换（100股为1手）
 */

#include "WtStraDualThrust.h"

#include "../Includes/ICtaStraCtx.h"

#include "../Includes/WTSContractInfo.hpp"
#include "../Includes/WTSVariant.hpp"
#include "../Includes/WTSDataDef.hpp"
#include "../Share/decimal.h"

extern const char* FACT_NAME;

//By Wesley @ 2022.01.05
#include "../Share/fmtlib.h"

/*!
 * \brief 构造函数
 * \param id 策略实例唯一标识符
 * 
 * \details 初始化DualThrust策略实例：
 *          - 调用基类构造函数设置策略ID
 *          - 成员变量将在init方法中从配置文件初始化
 */
WtStraDualThrust::WtStraDualThrust(const char* id)
	: CtaStrategy(id)
{
}

/*!
 * \brief 析构函数
 * 
 * \details 清理策略资源，释放内存
 */
WtStraDualThrust::~WtStraDualThrust()
{
}

/*!
 * \brief 获取策略工厂名称
 * \return 工厂名称字符串
 */
const char* WtStraDualThrust::getFactName()
{
	return FACT_NAME;
}

/*!
 * \brief 获取策略名称
 * \return 策略名称字符串
 */
const char* WtStraDualThrust::getName()
{
	return "DualThrust";
}

/*!
 * \brief 初始化策略参数
 * \param cfg 配置参数对象
 * \return 初始化成功返回true，失败返回false
 * 
 * \details 从配置文件中读取策略参数：
 *          - days: 历史数据天数，用于计算价格区间
 *          - k1: 上轨系数，控制做多入场敏感度
 *          - k2: 下轨系数，控制做空入场敏感度
 *          - period: K线周期（如"m1", "m5", "d1"）
 *          - count: K线数量，获取历史数据的条数
 *          - code: 交易合约代码
 *          - stock: 是否为股票交易模式
 */
bool WtStraDualThrust::init(WTSVariant* cfg)
{
	if (cfg == NULL)
		return false;

	_days = cfg->getUInt32("days");
	_k1 = cfg->getDouble("k1");
	_k2 = cfg->getDouble("k2");

	_period = cfg->getCString("period");
	_count = cfg->getUInt32("count");
	_code = cfg->getCString("code");

	_isstk = cfg->getBoolean("stock");

	return true;
}

/*!
 * \brief 策略调度事件处理
 * \param ctx 策略上下文
 * \param curDate 当前日期
 * \param curTime 当前时间
 * 
 * \details 核心策略逻辑实现，定时调度执行：
 *          
 *          执行步骤：
 *          1. 获取历史K线数据
 *          2. 计算DualThrust指标
 *          3. 判断交易信号
 *          4. 执行交易操作
 *          5. 记录交易日志
 *          
 *          交易逻辑：
 *          - 空仓状态：根据突破信号开仓
 *          - 多仓状态：根据下轨突破平仓
 *          - 空仓状态：根据上轨突破平仓（期货）
 *          
 *          风险控制：
 *          - 使用decimal精确比较浮点数
 *          - 自动释放K线数据内存
 *          - 股票模式自动转换交易单位
 */
void WtStraDualThrust::on_schedule(ICtaStraCtx* ctx, uint32_t curDate, uint32_t curTime)
{
	std::string code = _code;
	if (_isstk)
		code += "-";
	WTSKlineSlice *kline = ctx->stra_get_bars(code.c_str(), _period.c_str(), _count, true);
	if(kline == NULL)
	{
		// 如果获取数据失败，记录一些日志
		return;
	}

	if (kline->size() == 0)
	{
		kline->release();
		return;
	}

	uint32_t trdUnit = 1;
	if (_isstk)
		trdUnit = 100;	// 股票交易单位：100股为1手

	int32_t days = (int32_t)_days;

	// 计算DualThrust指标
	double hh = kline->maxprice(-days, -2);		// N天内最高价
	double ll = kline->minprice(-days, -2);		// N天内最低价

	WTSValueArray* closes = kline->extractData(KFT_CLOSE);
	double hc = closes->maxvalue(-days, -2);	// N天内最高收盘价
	double lc = closes->minvalue(-days, -2);	// N天内最低收盘价
	double curPx = closes->at(-1);				// 当前收盘价
	closes->release();	// !!!注意释放，一定要做

	double openPx = kline->at(-1)->open;		// 今日开盘价
	double highPx = kline->at(-1)->high;		// 今日最高价
	double lowPx = kline->at(-1)->low;			// 今日最低价

	// 计算上下轨
	double upper_bound = openPx + _k1 * (std::max(hh - lc, hc - ll));
	double lower_bound = openPx - _k2 * std::max(hh - lc, hc - ll);

	WTSCommodityInfo* commInfo = ctx->stra_get_comminfo(_code.c_str());

	double curPos = ctx->stra_get_position(_code.c_str()) / trdUnit;
	if(decimal::eq(curPos,0))
	{
		// 空仓状态，寻找开仓信号
		if(highPx >= upper_bound)
		{
			ctx->stra_enter_long(_code.c_str(), 2 * trdUnit, "DT_EnterLong");
			// 上轨突破，开多仓
			ctx->stra_log_info(fmt::format("上轨突破{}>={},开多仓进入", highPx, upper_bound).c_str());
		}
		else if (lowPx <= lower_bound && !_isstk)
		{
			ctx->stra_enter_short(_code.c_str(), 2 * trdUnit, "DT_EnterShort");
			// 下轨突破，开空仓（仅期货）
			ctx->stra_log_info(fmt::format("下轨突破{}<={},空仓进入", lowPx, lower_bound).c_str());
		}
	}
	//else if(curPos > 0)
	else if (decimal::gt(curPos, 0))
	{
		// 多仓状态，寻找平仓信号
		if(lowPx <= lower_bound)
		{
			// 多仓出场
			ctx->stra_exit_long(_code.c_str(), 2 * trdUnit, "DT_ExitLong");
			ctx->stra_log_info(fmt::format("下轨突破{}<={},多仓出场", lowPx, lower_bound).c_str());
		}
	}
	//else if(curPos < 0)
	else if (decimal::lt(curPos, 0))
	{
		// 空仓状态，寻找平仓信号
		if (highPx >= upper_bound && !_isstk)
		{
			// 空仓出场
			ctx->stra_exit_short(_code.c_str(), 2 * trdUnit, "DT_ExitShort");
			ctx->stra_log_info(fmt::format("上轨突破{}>={},空仓出场", highPx, upper_bound).c_str());
		}
	}

	ctx->stra_save_user_data("test", "waht");

	// 内存释放，一定要做
	kline->release();
}

/*!
 * \brief 策略初始化事件
 * \param ctx 策略上下文
 * 
 * \details 策略启动时调用，用于：
 *          - 数据订阅和初始化
 *          - 检查数据可用性
 *          - 预加载必要的历史数据
 */
void WtStraDualThrust::on_init(ICtaStraCtx* ctx)
{
	std::string code = _code;
	if (_isstk)
		code += "-";
	WTSKlineSlice *kline = ctx->stra_get_bars(code.c_str(), _period.c_str(), _count, true);
	if (kline == NULL)
	{
		// 如果获取数据失败，记录一些日志
		return;
	}

	kline->release();
}

/*!
 * \brief Tick数据事件处理
 * \param ctx 策略上下文
 * \param stdCode 标准合约代码
 * \param newTick 新的Tick数据
 * 
 * \details 接收到新Tick数据时调用：
 *          - DualThrust策略基于K线数据，不处理Tick
 *          - 可扩展实现基于Tick的实时信号监控
 */
void WtStraDualThrust::on_tick(ICtaStraCtx* ctx, const char* stdCode, WTSTickData* newTick)
{
	// 没有什么要处理的，DualThrust基于K线数据
}
